﻿using AngleSharp;
using AngleSharp.Parser.Html;
using LiteDB;
using NovelFetch.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Configuration;
using System.Web;
using AngleSharp.Dom.Html;
using Newtonsoft.Json;
using System.Diagnostics;

namespace NovelFetch
{
    public partial class MainForm : Form
    {
        private List<BookRule> _bookRules;
        private List<TextFilterRule> _textFilterRules;
        private string _currentRuleName;
        private static NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
        private static Regex _regex = new Regex(@"(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");
        //We require a custom configuration
        private IConfiguration _asConfig;
        private HtmlParser _htmlParser;
        private int _nChapterCount = 0;
        private static int _downLoadCount;
        private Thread _checkThread;
        List<KeyValuePair<string, string>> _siteNameUrlList;
        private string _savePath;
        private volatile bool _bCancelDownload;
        private static readonly object _lockObj = new Object();
        private Stopwatch _stopwatch;
        public MainForm()
        {
            InitializeComponent();
            _asConfig = AngleSharp.Configuration.Default.WithDefaultLoader();
            //_asConfig = _asConfig.WithJavaScript();
            _bCancelDownload = false;
            //Let's create a new parser using this configuration
            _htmlParser = new HtmlParser(_asConfig);
            var cfg = System.Configuration.ConfigurationManager.AppSettings;
            _savePath = cfg["SaveDir"];
            if (string.IsNullOrEmpty(_savePath))
            {
                _savePath = @".\Books\";
            }
            _stopwatch = new Stopwatch();
        }

        private void tsMenuAbout_Click(object sender, EventArgs e)
        {
            new AboutBox().ShowDialog();
        }

        private void tsMenuSiteRule_Click(object sender, EventArgs e)
        {
            new RuleForm().ShowDialog();
            InitData();

        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            folderBrowserDialog1.Description = "请选择小说保存目录";

            InitData();
        }

        private void InitData()
        {
            using (var db = new LiteDatabase(@"novel.db"))
            {
                var rules = db.GetCollection<BookRule>();
                rules.EnsureIndex(w => w.RuleName);
                _bookRules = new List<BookRule>();
                _textFilterRules = new List<TextFilterRule>();
                if (rules.Count() > 0)
                {
                    try
                    {
                        _bookRules = rules.FindAll().ToList();
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex);
                    }
                    _siteNameUrlList = new List<KeyValuePair<string, string>>();
                    foreach (var m in _bookRules)
                    {
                        _siteNameUrlList.Add(new KeyValuePair<string, string>(m.RuleName, m.SiteUrl));
                    }
                    cbNovelSiteName.DisplayMember = "Key";
                    cbNovelSiteName.ValueMember = "Value";
                    cbNovelSiteName.DataSource = _siteNameUrlList;
                }
                var filterRuleCollects = db.GetCollection<TextFilterRule>();
                if (filterRuleCollects.Count() > 0)
                {
                    try
                    {
                        _textFilterRules = filterRuleCollects.FindAll().ToList();
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex);
                    }
                }
            }

            if (!Directory.Exists("tmp"))
            {
                Directory.CreateDirectory("tmp");
            }
            if (!Directory.Exists(_savePath))
            {
                Directory.CreateDirectory(_savePath);
            }
        }
        private void cbNovelSiteName_SelectedIndexChanged(object sender, EventArgs e)
        {
            var selVal = cbNovelSiteName.SelectedValue?.ToString();
            if (!string.IsNullOrEmpty(selVal))
            {
                lbInfo.Text = "当前站点URL:" + selVal;
            }
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            var selVal = cbNovelSiteName.SelectedValue?.ToString();
            if (string.IsNullOrEmpty(selVal))
            {
                MessageBox.Show("请先选择一个站点!", "提示");
                return;
            }
            var pageUrl = tbNovelUrl.Text;
            if (string.IsNullOrEmpty(pageUrl))
            {
                MessageBox.Show("请输入小说页面URL!", "提示");
                tbNovelUrl.Focus();
                return;
            }
            var urlRegx = new Regex("(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");
            if (!urlRegx.IsMatch(pageUrl))
            {
                MessageBox.Show("小说页面URL错误!", "提示");
                tbNovelUrl.Focus();
                return;
            }
            bool bFind = false;
            for (int i = 0; i < _siteNameUrlList.Count; i++)
            {
                var kv = _siteNameUrlList[i];
                if (pageUrl.Contains(kv.Value))
                {
                    cbNovelSiteName.SelectedIndex = i;
                    _currentRuleName = kv.Key;
                    bFind = true;
                    break;
                }
            }

            if (!bFind)
            {
                MessageBox.Show("您输入的站点尚未设置规则,请设置好规则后再试!", "提示");
                return;
            }
            listView1.Items.Clear();
            LoadUrl(tbNovelUrl.Text);
        }


        private void LoadUrl(string url)
        {
            try
            {
                
                var document = BrowsingContext.New(_asConfig).OpenAsync(url);
                document.Wait();
                var rule = _bookRules.Find(w => w.RuleName == _currentRuleName);
                if (rule == null)
                {
                    MessageBox.Show("没有设置该站点规则!", "提示");
                    return;
                }
                //小说名规则
                var title = document.Result.QuerySelector(rule.TitleRule);
                if (string.IsNullOrEmpty(title.TextContent))
                {
                    if (MessageBox.Show("无法获取小说标题,请检查是否规则错误!\n 是否手动输入标题?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
                    {
                        tbTitleName.ReadOnly = false;
                        tbTitleName.Focus();
                    }
                    return;
                }
                else
                {
                    tbTitleName.Text = title.TextContent;
                }


                // 根据class获取html元素
                _downLoadCount = 0;
                var catalogs = document.Result.QuerySelectorAll(rule.CatalogRule);
                if (catalogs.Count() > 0)
                {
                    //AngleSharp.Dom.Html.HtmlAnchorElement
                    foreach (var obj in catalogs)
                    {
                        ListViewItem lvItem;

                        if (obj is AngleSharp.Dom.Html.HtmlAnchorElement)
                        {
                            var hae = obj as AngleSharp.Dom.Html.HtmlAnchorElement;
                            lvItem = new ListViewItem(new string[] { obj.TextContent, hae.Href, "就绪" });
                        }
                        else if (obj is HtmlUrlBaseElement)
                        {
                            var ube = obj as HtmlUrlBaseElement;
                            lvItem = new ListViewItem(new string[] { obj.TextContent, ube.Href, "就绪" });
                        }
                        else
                        {
                            var captUrl = obj.BaseUri;

                            var href = obj.GetAttribute("href");
                            if (string.IsNullOrEmpty(href))
                            {
                                captUrl = "url错误";
                            }
                            else
                            {
                                if (href.StartsWith("./"))
                                {
                                    captUrl += href.TrimStart(new char[] { '.', '/' });
                                }
                            }
                            lvItem = new ListViewItem(new string[] { obj.TextContent, captUrl, "就绪" });
                        }


                        listView1.Items.Add(lvItem);
                    }
                    _nChapterCount = catalogs.Count();
                    nudDownRangeCeiling.Maximum = _nChapterCount;

                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "无法获取小说信息");
                MessageBox.Show("规则设置错,无法获取小说信息");
            }

        }

        private void tsMenuSellectAll_Click(object sender, EventArgs e)
        {
            ListViewCheckBox(1);
        }

        private void tsMenuReSelect_Click(object sender, EventArgs e)
        {
            ListViewCheckBox(2);
        }

        private void tsMenuCancelSelectAll_Click(object sender, EventArgs e)
        {
            ListViewCheckBox(0);
        }

        /// <summary>
        /// 修改ListView中checkbox状态
        /// 0:取消全选
        /// 1:全选
        /// 2:反选
        /// </summary>
        /// <param name="status"></param>
        private void ListViewCheckBox(int status)
        {
            for (var i = 0; i < listView1.Items.Count; i++)
            {
                var item = listView1.Items[i];
                switch (status)
                {
                    case 0:
                        item.Checked = false;
                        break;
                    case 1:
                        item.Checked = true;
                        break;
                    case 2:
                        item.Checked = !item.Checked;
                        break;
                }
            }
        }

        private void btnDownLoadSelect_Click(object sender, EventArgs e)
        {
            if (listView1.CheckedIndices.Count < 1)
            {
                MessageBox.Show("请最少选择一个章节下载!", "提示");
                return;
            }
            DownLoadChapter(1);
        }

        private void btnDownLoadAll_Click(object sender, EventArgs e)
        {
            DownLoadChapter(0);
        }

        /// <summary>
        /// 下载内容
        /// </summary>
        /// <param name="nDownloadOpt">下载选项,0:下载全部,1:下载所选,2:下载传入区段</param>
        /// <param name="startIndex">开始下载章节索引</param>
        /// <param name="length">下载长度</param>
        private void DownLoadChapter(int nDownloadOpt, int startIndex = 0, int length = -1)
        {
            if (listView1.Items.Count < 1)
            {
                MessageBox.Show("请先获取小说章节目录", "提示");
                return;
            }
            _stopwatch.Reset();
            _stopwatch.Start();
            _bCancelDownload = false;
            if (startIndex < 0)
            {
                startIndex = 0;
            }
            if (length > listView1.Items.Count)
            {
                length = listView1.Items.Count - 1;
            }
            try
            {
                var list = new List<string>();
                var rule = _bookRules.Find(w => w.RuleName == _currentRuleName);
                _downLoadCount = 0;
                int index = startIndex;
                int len = listView1.Items.Count;
                switch (nDownloadOpt)
                {
                    case 0:
                        _nChapterCount = listView1.Items.Count;
                        break;
                    case 1:
                        _nChapterCount = listView1.CheckedIndices.Count;
                        break;
                    case 2:
                        if (length == -1) //下载到最后章节
                        {

                            len = len - startIndex;
                        }
                        else
                        {

                            if (length > len - startIndex)
                            {
                                len = len - startIndex;
                            }
                            else
                            {
                                len = length;
                            }
                        }
                        _nChapterCount = len;

                        break;
                    default:
                        lbInfo.Text = "选项错误!";
                        return;
                }
                tsProgressBar.Maximum = len;
                tsProgressBar.Value = 0;
                int endIndex = startIndex + len;
                for (var i = index; i < endIndex; i++)
                {
                    if (_bCancelDownload) break;
                    var item = listView1.Items[i];
                    var title = item.SubItems[0].Text;
                    var url = item.SubItems[1].Text;
                    if (!_regex.IsMatch(url))
                    {
                        item.SubItems[2].Text = "URL错误";
                        _logger.Info("不匹配URL规则", $"章节名:{item.SubItems[0].Text},URL:{url}");
                        continue;
                    }


                    if (nDownloadOpt == 1)
                    {
                        if (item.Checked)
                        {
                            var threadParam = new ThreadParam()
                            {
                                Url = url,
                                ListViewIndex = i,
                                ContentRule = rule.ContentRule,
                                HeaderSkipNum = rule.HeaderSkipLine,
                                FooterSkipNum = rule.FooterSkipLine
                            };
                            if (!string.IsNullOrEmpty(title))
                            {
                                threadParam.Title = title;
                            }
                            ThreadPool.QueueUserWorkItem(LoadHtmlContent, threadParam);

                        }
                        continue;
                    }
                    else //下载全部或者指定区间
                    {
                        var threadParam = new ThreadParam()
                        {
                            Url = url,
                            ListViewIndex = i,
                            ContentRule = rule.ContentRule,

                        };
                        if (!string.IsNullOrEmpty(title))
                        {
                            threadParam.Title = title;
                        }
                        item.SubItems[2].Text = "下载中...";
                        ThreadPool.QueueUserWorkItem(LoadHtmlContent, threadParam);
                        continue;
                    }

                }

                if (_checkThread != null && _checkThread.IsAlive)
                {
                    if (!_checkThread.Join(3 * 1000))
                    {
                        _checkThread.Abort();
                    }
                    _checkThread = null;
                }

                _checkThread = new Thread(new ThreadStart(CheckWorkFinish));
                _checkThread.IsBackground = true;
                _checkThread.Start();
            }
            catch (Exception ex)
            {
                lbInfo.Text = "下载出错!";
                _logger.Error(ex, "下载出错!");
            }

        }


        /// <summary>
        /// 解析章节内容
        /// </summary>
        /// <param name="stateInfo"></param>
        private void LoadHtmlContent(Object stateInfo)
        {
            //_htmlParser.

            var param = stateInfo as ThreadParam;
            if (param == null) return;
            if (string.IsNullOrEmpty(param.ContentRule)) return;
            if (_bCancelDownload)
            {
                UpdateDownLoadStatus(param.ListViewIndex, "取消下载");
                return;
            }
            var title = param.Title;
            if (string.IsNullOrEmpty(title))
            {
                title = "章节标题不存在";
            }
            try
            {


                var document = BrowsingContext.New(_asConfig).OpenAsync(param.Url);
                //document.Result.Dispatch(new AngleSharp.Dom.Events.CustomEvent("hello"));
                //var e = document.CreateEvent("event");
                //e.Init("whenCompleted", false, false);
                //document.Result.Dispatch(e);
                //document.AddEventListener

                // document.Wait();
                var catalog = document.Result.QuerySelector(param.ContentRule);

                // 根据class获取html元素
                var catalogs = document.Result.QuerySelectorAll(param.ContentRule);
                var contentLines = catalogs.Count();
                if (contentLines > 0)
                {
                    StringBuilder strBuf = new StringBuilder();
                    strBuf.AppendLine(title);
                    int idx = param.HeaderSkipNum;
                    int len = contentLines - param.FooterSkipNum;
                    len = len == 0 ? 1 : len;
                    if (idx > contentLines)
                    {
                        idx = 0;
                    }
                    for (int i = idx; i < len; i++)
                    {
                        var text = "";
                        lock (_lockObj)
                        {
                            var obj = catalogs[i];
                            text = obj.TextContent;
                        }

                        var textContent = HttpUtility.HtmlDecode(text);

                        strBuf.AppendLine(TextContentFilter(textContent));

                    }
                    using (var txtFile = File.CreateText($".\\tmp\\{param.ListViewIndex}.txt"))
                    {
                        txtFile.Write(strBuf.ToString());
                        strBuf.Clear();
                    }
                    UpdateDownLoadStatus(param.ListViewIndex, "下载完成");
                    document.Result.Close();
                    document.Result.Dispose();
                }
                else
                {
                    UpdateDownLoadStatus(param.ListViewIndex, "下载失败");
                }

                lock (_lockObj)
                {
                    UpdateProgressBar();
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"下载出错,URL:{param.Url}");
                UpdateDownLoadStatus(param.ListViewIndex, "下载出错");
            }
            finally
            {
                Interlocked.Increment(ref _downLoadCount);
            }


        }



        /// <summary>
        /// 内容过滤处理
        /// </summary>
        /// <param name="orgText">原文</param>
        /// <returns></returns>
        private string TextContentFilter(string orgText)
        {
            if (string.IsNullOrEmpty(orgText)) return "";
            var processText = orgText;
            try
            {
                processText = NoHTML(processText);
                foreach (var rule in _textFilterRules)
                {
                    if (rule.IsSupportRegex)
                    {

                        Regex textRegex = new Regex(rule.OrgText);
                        processText = textRegex.Replace(processText, rule.ReplaceText ?? "");
                    }
                    else
                    {
                        processText = processText.Replace(rule.OrgText, rule.ReplaceText ?? "");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "文本过滤出错");
                return orgText;
            }
            return processText;
        }

        /// <summary>
        /// 检测是否全部完成
        /// </summary>
        private void CheckWorkFinish()
        {
            while (true)
            {
                if (Interlocked.CompareExchange(ref _downLoadCount, _nChapterCount, _nChapterCount) >= _nChapterCount)
                {
                    //全部下载完毕,合并文件
                    try
                    {
                        UpdateStatusLable("正在合并文件,请稍后...");
                        var tmpDir = new DirectoryInfo(@".\tmp\");
                        var txtFiles = tmpDir.EnumerateFiles("*.txt").OrderBy(w =>
                        {
                            var name = Path.GetFileNameWithoutExtension(w.Name);
                            int.TryParse(name, out int num);
                            return num;
                        }).ToList();
                        var fileName = string.Format("{0}_{1}.txt", tbTitleName.Text, DateTime.Now.ToString("yyyy-MM-dd_HH#mm"));
                        var novelFullName = Path.Combine(_savePath, fileName);

                        using (var novelFile = File.CreateText(novelFullName))
                        {
                            StringBuilder txtBuf = new StringBuilder();
                            foreach (var f in txtFiles)
                            {
                                var str = File.ReadAllText(f.FullName);
                                txtBuf.AppendLine(str);
                                File.Delete(f.FullName);
                            }
                            novelFile.Write(txtBuf.ToString());
                        }
                        
                        UpdateStatusLable($"小说{tbTitleName.Text}下载完毕!");
                        GC.Collect();
                        _stopwatch.Stop();
                        MessageBox.Show($"下载完成，耗时：{_stopwatch.ElapsedMilliseconds}(毫秒)", "提示");
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex, "合并文件异常");
                        UpdateStatusLable("合并文件失败!");
                    }
                    break;
                }
                else
                {
                    Thread.Sleep(100);
                }
            }

        }

        private void UpdateDownLoadStatus(int index, string msg)
        {
            if (listView1.InvokeRequired)
            {
                Action<int, string> act = (i, s) => { listView1.Items[index].SubItems[2].Text = msg; };
                listView1.Invoke(act, index, msg);
            }
            else
            {
                listView1.Items[index].SubItems[2].Text = msg;
            }

        }

        private void UpdateProgressBar()
        {
            if (tsProgressBar.ProgressBar.InvokeRequired)
            {
                Action act = () =>
                {
                    tsProgressBar.PerformStep();
                };
                tsProgressBar.ProgressBar.Invoke(act);
            }
            else
            {
                tsProgressBar.PerformStep();
            }
        }

        private void UpdateStatusLable(string msg)
        {
            if (statusStrip1.InvokeRequired)
            {
                Action<string> act = (s) => { lbInfo.Text = s; };
                listView1.Invoke(act, msg);
            }
            else
            {
                lbInfo.Text = msg;
            }
        }
        private void threadNumUpDown_ValueChanged(object sender, EventArgs e)
        {
            var num = (int)threadNumUpDown.Value;
            ThreadPool.SetMaxThreads(num, num);
        }

        private void tsMenuTxtFilter_Click(object sender, EventArgs e)
        {
            new FilterForm().ShowDialog();
            InitData();
        }

        private void tsMenuSavePath_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                MessageBox.Show("小说保存目录变更成功", "提示");
                _savePath = folderBrowserDialog1.SelectedPath;

                var cfg = System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                cfg.AppSettings.Settings["SaveDir"].Value = _savePath;
                cfg.Save(ConfigurationSaveMode.Modified);
            }
        }

        private void btnDownloadRange_Click(object sender, EventArgs e)
        {
            var floor = (int)nudDownRangeFloor.Value;
            var ceiling = (int)nudDownRangeCeiling.Value;

            DownLoadChapter(2, floor, ceiling);
        }

        public static string NoHTML(string Htmlstring)
        {

            //删除脚本  &amp;sect;  

            Htmlstring = Htmlstring.Replace("&sect;", "");
            Htmlstring = Htmlstring.Replace("&mdash;", "-");
            Htmlstring = Htmlstring.Replace("&middot;", ".");
            Htmlstring = Htmlstring.Replace("<br>", "\n");
            Htmlstring = Htmlstring.Replace("</br>", "\n");
            Htmlstring = Regex.Replace(Htmlstring, @"<script[^>]*?>.*?</script>", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&(quot|#34);", "\"", RegexOptions.IgnoreCase);

            //  Htmlstring = Regex.Replace(Htmlstring, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);  

            Htmlstring = Regex.Replace(Htmlstring, @"&(lt|#60);", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&(gt|#62);", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&(nbsp|#160);", " ", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&(iexcl|#161);", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&(cent|#162);", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&(pound|#163);", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&(copy|#169);", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"&#(/d+);", "", RegexOptions.IgnoreCase);
            //删除HTML    

            Htmlstring = Regex.Replace(Htmlstring, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);

            Htmlstring = Regex.Replace(Htmlstring, @"([/r/n])[/s]+", "", RegexOptions.IgnoreCase);

            Htmlstring = Htmlstring.Trim();

            return Htmlstring;

        }

        /// <summary>
        /// 导出站点规则
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsMenuExportSiteRule_Click(object sender, EventArgs e)
        {
            try
            {

                var jsonBookRules = JsonConvert.SerializeObject(_bookRules);
                saveFileDialog1.FileName = $"{DateTime.Now.ToString("导出规则yyyy-MM-dd")}";
                saveFileDialog1.DefaultExt = "rule";
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    using (var file = File.CreateText(saveFileDialog1.FileName))
                    {
                        file.Write(jsonBookRules);
                    }
                    MessageBox.Show($"导出成功!\n文件路径:{saveFileDialog1.FileName}", "导出提示");
                }
            }
            catch (Exception ex)
            {

                _logger.Error(ex);
            }

        }

        /// <summary>
        /// 导入站点规则
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsMenuImportSiteRule_Click(object sender, EventArgs e)
        {
            try
            {
                openFileDialog1.DefaultExt = "rule";
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    var jsonText = File.ReadAllText(openFileDialog1.FileName);
                    if (!string.IsNullOrEmpty(jsonText))
                    {
                        var bookRules = JsonConvert.DeserializeObject<List<BookRule>>(jsonText);
                        using (var db = new LiteDatabase(@"novel.db"))
                        {
                            var rules = db.GetCollection<BookRule>();

                            rules.Upsert(bookRules);
                        }
                    }
                    MessageBox.Show($"导入成功!", "导入提示");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"导入失败!你选择的不是规则文件.", "导入提示");
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// 导出文本过滤列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsMenuExportTextFilterList_Click(object sender, EventArgs e)
        {
            try
            {

                var jsonTextFilter = JsonConvert.SerializeObject(_textFilterRules);
                saveFileDialog1.DefaultExt = "filter";
                saveFileDialog1.FileName = $"{DateTime.Now.ToString("导出过滤列表yyyy-MM-dd")}";
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    using (var file = File.CreateText(saveFileDialog1.FileName))
                    {
                        file.Write(jsonTextFilter);
                    }
                    MessageBox.Show($"导出成功!\n文件路径:{saveFileDialog1.FileName}", "导出提示");
                }
            }
            catch (Exception ex)
            {

                _logger.Error(ex);
            }
        }

        /// <summary>
        /// 导入文本过滤列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsMenuImportTextFilterList_Click(object sender, EventArgs e)
        {
            try
            {
                openFileDialog1.DefaultExt = "filter";
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    var jsonText = File.ReadAllText(openFileDialog1.FileName);
                    if (!string.IsNullOrEmpty(jsonText))
                    {
                        var textFilters = JsonConvert.DeserializeObject<List<TextFilterRule>>(jsonText);
                        using (var db = new LiteDatabase(@"novel.db"))
                        {
                            var rules = db.GetCollection<TextFilterRule>();

                            rules.Upsert(textFilters);
                        }
                    }
                    MessageBox.Show($"导入成功!", "导入提示");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"导入失败,你选择的不是文本过滤列表!", "导入提示");
                _logger.Error(ex);
            }
        }

        private void btnCancelDownload_Click(object sender, EventArgs e)
        {
            _bCancelDownload = true;
            lbInfo.Text = "取消下载";
        }
    }

    class ThreadParam
    {
        //var rule = _bookRules.Find(w => w.RuleName == _currentRuleName);
        public string Url { get; set; }

        /// <summary>
        /// 标题
        /// </summary>
        public string Title { get; set; }


        /// <summary>
        /// 内容规则
        /// </summary>
        public string ContentRule { get; set; }

        /// <summary>
        /// ListView中位置
        /// </summary>
        public int ListViewIndex { get; set; }

        /// <summary>
        /// 内容头部跳过行数
        /// </summary>
        public int HeaderSkipNum { get; set; }

        /// <summary>
        /// 内容尾部跳过行数
        /// </summary>
        public int FooterSkipNum { get; set; }
    }
}
